class Snake {
  // 表示蛇头的元素
  head: HTMLElement;
  // 蛇的身体包括蛇头
  bodies: HTMLCollection;
  // 获取蛇的容器
  element: HTMLElement
  constructor() {
    this.element = document.querySelector('.snake')!;
    // 直接获取snake容器里面的div
    this.head = document.querySelector('.snake > div') as HTMLElement;
    // getElementsByTagName获取的是 HTMLCollection
    this.bodies = this.element!.getElementsByTagName('div')
  }

  // 获取蛇的坐标（蛇头的横纵坐标）
  get X() {
    return this.head.offsetLeft;

  }
  get Y() {
    return this.head.offsetTop;
  }

  // 设置蛇头的横向坐标
  set X(value: number) {
    if (this.X === value) {
      return;
    }
    if (value < 0 || value > 290) {
      // 蛇撞墙了,抛出异常
      throw new Error('蛇撞墙了');
    }
    
    if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
      // 如果发生掉头反方向继续走
      if (value > this.X) {
        // 如果新值大于旧值X,则说明修改方向掉头想让蛇向右走，阻止掉头应该让蛇向左走,向左走value值减少
        value = this.X - 10
      } else {
        value = this.X + 10
      }
    }
    // 移动身体
    this.moveBody();

    this.head.style.left = value + 'px'

    // 检查蛇头是否撞到了身体
    this.checkHeadBody()
  }
  // 设置蛇的纵向坐标
  set Y(value: number) {
    if (this.Y === value) {
      return;
    }
    // 判断Y值是否合法
    if (value < 0 || value > 290) {
      // 蛇撞墙了
      throw new Error('蛇撞墙了');
    }
    if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
      console.log('水平方向掉头');
      // 如果发生掉头修正的话让蛇反方向继续走
      if (value > this.Y) {
        // 如果新值大于旧值Y,则说明修改方向掉头想让蛇向上走，阻止掉头应该让蛇向下走
        value = this.Y - 10;
      } else {
        value = this.Y + 10;
      }
    }
    // 移动蛇的身体
    this.moveBody();
    this.head.style.top = value + 'px';
    this.checkHeadBody();
  }

  // 蛇增加身体的方法
  addBody() {
    // 向element里面添加一个div
    this.element.insertAdjacentHTML('beforeend', "<div></div>")
  }

  // 蛇身体移动的方法
  moveBody() {
    // 将后面的身体设置为前面身体的位置；第四节身体位置设置为第三节的位置以此类推
    for (let i = this.bodies.length - 1; i > 0; i--) {
      // 获取当前身体的前一个身体的位置(需要用到类型断言)
      let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
      let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;
      // 将获取到的值设置到当前身体上
      (this.bodies[i] as HTMLElement).style.left = X + 'px';
      (this.bodies[i] as HTMLElement).style.top = Y + 'px'
    }
  }

  checkHeadBody() {
    // 获取所有身体坐标检查是否和蛇头的坐标发生重叠
    for (let i = 1; i < this.bodies.length; i++) {
      let body = this.bodies[i] as HTMLElement
      if (this.X === body.offsetLeft && this.Y === body.offsetTop) {
        // 进入判断意味着蛇头撞到了身体,游戏结束
        throw new Error('撞到自己了 game over' )
      }
    }
  }
}

export default Snake;